package common

import (
	"encoding/json"
	"errors"
	"fmt"
	"reflect"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
)

type CommonListRsp struct {
	Code       uint   `json:"code"`
	Msg        string `json:"msg"`
	PageSize   uint   `json:"page_size"`
	PageIndex  uint   `json:"page_index"`
	TotalCount uint   `json:"total_count"`
}

// ------------------------------------------------------------------------------
//
// ------------------------------------------------------------------------------
func StructToKeyArray(s interface{}) []string {
	var arr []string
	v := reflect.ValueOf(s)
	for i := 0; i < v.NumField(); i++ {
		arr = append(arr, v.Type().Field(i).Name)
	}
	return arr
}

// ------------------------------------------------------------------------------
//
// ------------------------------------------------------------------------------
func InvalidParamRspMsg(param any) string {
	return fmt.Sprintf("invalid request, parameters must in:%s", StructToKeyArray(param))
}

// ------------------------------------------------------------------------------
//
// ------------------------------------------------------------------------------
func GetRequestIntParam(c *gin.Context, param string) (int, error) {
	data := c.Query(param)
	if data == "" {
		return 0, nil
	}

	num, err := strconv.Atoi(data)
	if err != nil {
		return 0, fmt.Errorf("invalid parameter:%s", param)
	}

	return num, nil
}

// ------------------------------------------------------------------------------
//
// ------------------------------------------------------------------------------
func MustGetRequestIntParam(c *gin.Context, param string) (int, error) {
	data := c.Query(param)
	if data == "" {
		return 0, NewErrCode(ErrGeneralError)
	}

	num, err := strconv.Atoi(data)
	if err != nil {
		return 0, fmt.Errorf("invalid parameter:%s", param)
	}

	return num, nil
}

// ------------------------------------------------------------------------------
//
// ------------------------------------------------------------------------------
func CheckPageSizeAndIndex(c *gin.Context) (int, int, error) {
	pageSize, err := MustGetRequestIntParam(c, "page_size")
	if err != nil {
		return 0, 0, errors.New("cannot find page_size parameter")
	}

	pageIndex, err := MustGetRequestIntParam(c, "page_index")
	if err != nil {
		return 0, 0, errors.New("cannot find page_index parameter")
	}

	return pageSize, pageIndex, nil
}

// ------------------------------------------------------------------------------
//
// ------------------------------------------------------------------------------
func GetUserName(c *gin.Context) string {
	userNameValue, exists := c.Get("user_name")
	if !exists {
		return "unknown"
	}

	userName, ok := userNameValue.(string)
	if !ok {
		return "unknown"
	}

	return userName
}

// ------------------------------------------------------------------------------
// set implementation
// ------------------------------------------------------------------------------
type Set map[interface{}]bool

func (s Set) Add(item interface{}) {
	s[item] = true
}

func (s Set) Remove(item interface{}) {
	delete(s, item)
}

func (s Set) Contains(item interface{}) bool {
	_, exists := s[item]
	return exists
}

func (s Set) Size() int {
	return len(s)
}

// ------------------------------------------------------------------------------
//
// ------------------------------------------------------------------------------
func MustMarshal(v interface{}) string {
	data, err := json.Marshal(v)
	if err != nil {
		panic(err)
	}
	return string(data)
}

// ------------------------------------------------------------------------------
//
// ------------------------------------------------------------------------------
func DefTopoViewName(moduleName string) string {
	return moduleName + "-topo-view"
}

// ------------------------------------------------------------------------------
//
// ------------------------------------------------------------------------------
func TimeFormat(t time.Time) string {
	return t.Format("2006-01-02 15:04:05")
}
